{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import altair as alt\n",
    "\n",
    "\n",
    "def make_bars_chart(df, title, scale_title=None, avg_col='avg', sqrt_scale=True,\n",
    "                   width=50, height=300, multi_bar=True, legend=True, labels=True):\n",
    "    source = df.copy()\n",
    "\n",
    "    if source[avg_col].max() > 1:\n",
    "        avg_scale = 'secs'\n",
    "        avg_coef = 1\n",
    "    elif source[avg_col].max() > 0.001:\n",
    "        avg_scale = 'ms'\n",
    "        avg_coef = 1e3\n",
    "    else:\n",
    "        avg_scale = 'µs'\n",
    "        avg_coef = 1e6\n",
    "\n",
    "    source[avg_scale] = (df[avg_col] * avg_coef).round(2)\n",
    "    \n",
    "    if not scale_title:\n",
    "        scale_titles = {\n",
    "            'secs': 'seconds',\n",
    "            'ms': 'milliseconds (1e−3 secs)',\n",
    "            'µs': 'microseconds (1e−6 secs)',\n",
    "        }\n",
    "        scale_title = scale_titles[avg_scale]\n",
    "\n",
    "    if sqrt_scale:\n",
    "        y_scale = alt.Scale(type='sqrt')\n",
    "    else:\n",
    "        y_scale = alt.Scale()\n",
    "    \n",
    "    if multi_bar:\n",
    "        x_val = 'bench:N'\n",
    "        facet_kwds = {'column':'name:N'}\n",
    "    else:\n",
    "        x_val = 'name:N'\n",
    "        facet_kwds = {}\n",
    "\n",
    "    if legend:\n",
    "        legend = alt.Legend()\n",
    "    else:\n",
    "        legend = None\n",
    "\n",
    "    chart = alt.Chart(\n",
    "        width=width,\n",
    "        height=height,\n",
    "    ).mark_bar(\n",
    "        stroke='transparent',\n",
    "        size=20,\n",
    "    ).encode(\n",
    "        alt.X(x_val, scale=alt.Scale(), axis=alt.Axis(title='', labels=labels)),\n",
    "        alt.Y(f'{avg_scale}:Q', scale=y_scale, axis=alt.Axis(title=scale_title, grid=False)),\n",
    "        color=alt.Color(x_val, scale=alt.Scale(range=[\"#FF7B06\", \"#094AFB\", \"#D60000\"]), legend=legend),\n",
    "    )\n",
    "\n",
    "    text = chart.mark_text(\n",
    "        color='black',\n",
    "        dx = 0,\n",
    "        dy = -2,\n",
    "    ).encode(\n",
    "        text=f'{avg_scale}:Q'\n",
    "    )\n",
    "\n",
    "    return alt.layer(chart, text, data=source).facet(\n",
    "        **facet_kwds\n",
    "    ).configure_axis(\n",
    "        domainWidth=0.8,\n",
    "    ).configure_view(\n",
    "        stroke='transparent'\n",
    "    ).properties(\n",
    "        title=title\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>bench</th>\n",
       "      <th>max</th>\n",
       "      <th>mean</th>\n",
       "      <th>min</th>\n",
       "      <th>std</th>\n",
       "      <th>tool</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1-8digits</td>\n",
       "      <td>0.579355</td>\n",
       "      <td>0.556693</td>\n",
       "      <td>0.538694</td>\n",
       "      <td>0.012929</td>\n",
       "      <td>cracken</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1-8digits</td>\n",
       "      <td>0.715639</td>\n",
       "      <td>0.687277</td>\n",
       "      <td>0.667732</td>\n",
       "      <td>0.011805</td>\n",
       "      <td>maskprocessor</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>9digits</td>\n",
       "      <td>5.045765</td>\n",
       "      <td>4.826192</td>\n",
       "      <td>4.673063</td>\n",
       "      <td>0.110049</td>\n",
       "      <td>cracken</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>9digits</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>NaN</td>\n",
       "      <td>crunch</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>9digits</td>\n",
       "      <td>6.241444</td>\n",
       "      <td>6.001537</td>\n",
       "      <td>5.862338</td>\n",
       "      <td>0.101060</td>\n",
       "      <td>maskprocessor</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       bench         max        mean         min       std           tool\n",
       "0  1-8digits    0.579355    0.556693    0.538694  0.012929        cracken\n",
       "1  1-8digits    0.715639    0.687277    0.667732  0.011805  maskprocessor\n",
       "2    9digits    5.045765    4.826192    4.673063  0.110049        cracken\n",
       "3    9digits  184.738300  184.738300  184.738300       NaN         crunch\n",
       "4    9digits    6.241444    6.001537    5.862338  0.101060  maskprocessor"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "single_df = pd.read_json('bench_results.json', orient='records')\n",
    "single_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>bench</th>\n",
       "      <th>tool</th>\n",
       "      <th>max</th>\n",
       "      <th>mean</th>\n",
       "      <th>min</th>\n",
       "      <th>std</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1-8digits</td>\n",
       "      <td>cracken</td>\n",
       "      <td>0.579355</td>\n",
       "      <td>0.556693</td>\n",
       "      <td>0.538694</td>\n",
       "      <td>0.012929</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1-8digits</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>0.715639</td>\n",
       "      <td>0.687277</td>\n",
       "      <td>0.667732</td>\n",
       "      <td>0.011805</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>9digits</td>\n",
       "      <td>cracken</td>\n",
       "      <td>5.045765</td>\n",
       "      <td>4.826192</td>\n",
       "      <td>4.673063</td>\n",
       "      <td>0.110049</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>9digits</td>\n",
       "      <td>crunch</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>9digits</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>6.241444</td>\n",
       "      <td>6.001537</td>\n",
       "      <td>5.862338</td>\n",
       "      <td>0.101060</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>upper-5lower-digit</td>\n",
       "      <td>cracken</td>\n",
       "      <td>15.212566</td>\n",
       "      <td>14.847242</td>\n",
       "      <td>14.769393</td>\n",
       "      <td>0.138524</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>upper-5lower-digit</td>\n",
       "      <td>crunch</td>\n",
       "      <td>474.109697</td>\n",
       "      <td>474.109697</td>\n",
       "      <td>474.109697</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>upper-5lower-digit</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>19.390088</td>\n",
       "      <td>19.144515</td>\n",
       "      <td>18.525928</td>\n",
       "      <td>0.293365</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                bench           tool         max        mean         min  \\\n",
       "0           1-8digits        cracken    0.579355    0.556693    0.538694   \n",
       "1           1-8digits  maskprocessor    0.715639    0.687277    0.667732   \n",
       "2             9digits        cracken    5.045765    4.826192    4.673063   \n",
       "3             9digits         crunch  184.738300  184.738300  184.738300   \n",
       "4             9digits  maskprocessor    6.241444    6.001537    5.862338   \n",
       "5  upper-5lower-digit        cracken   15.212566   14.847242   14.769393   \n",
       "6  upper-5lower-digit         crunch  474.109697  474.109697  474.109697   \n",
       "7  upper-5lower-digit  maskprocessor   19.390088   19.144515   18.525928   \n",
       "\n",
       "        std  \n",
       "0  0.012929  \n",
       "1  0.011805  \n",
       "2  0.110049  \n",
       "3       NaN  \n",
       "4  0.101060  \n",
       "5  0.138524  \n",
       "6       NaN  \n",
       "7  0.293365  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = single_df.groupby(['bench', 'tool']).mean().reset_index()\n",
    "df['tool'].replace('crunch', ' crunch', inplace=True)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>bench</th>\n",
       "      <th>tool</th>\n",
       "      <th>max</th>\n",
       "      <th>mean</th>\n",
       "      <th>min</th>\n",
       "      <th>std</th>\n",
       "      <th>secs</th>\n",
       "      <th>name</th>\n",
       "      <th>ms</th>\n",
       "      <th>µs</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1-8digits</td>\n",
       "      <td>cracken</td>\n",
       "      <td>0.579355</td>\n",
       "      <td>0.556693</td>\n",
       "      <td>0.538694</td>\n",
       "      <td>0.012929</td>\n",
       "      <td>0.556693</td>\n",
       "      <td>cracken</td>\n",
       "      <td>556.692714</td>\n",
       "      <td>5.566927e+05</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1-8digits</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>0.715639</td>\n",
       "      <td>0.687277</td>\n",
       "      <td>0.667732</td>\n",
       "      <td>0.011805</td>\n",
       "      <td>0.687277</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>687.276880</td>\n",
       "      <td>6.872769e+05</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>9digits</td>\n",
       "      <td>cracken</td>\n",
       "      <td>5.045765</td>\n",
       "      <td>4.826192</td>\n",
       "      <td>4.673063</td>\n",
       "      <td>0.110049</td>\n",
       "      <td>4.826192</td>\n",
       "      <td>cracken</td>\n",
       "      <td>4826.191874</td>\n",
       "      <td>4.826192e+06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>9digits</td>\n",
       "      <td>crunch</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>NaN</td>\n",
       "      <td>184.738300</td>\n",
       "      <td>crunch</td>\n",
       "      <td>184738.299608</td>\n",
       "      <td>1.847383e+08</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>9digits</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>6.241444</td>\n",
       "      <td>6.001537</td>\n",
       "      <td>5.862338</td>\n",
       "      <td>0.101060</td>\n",
       "      <td>6.001537</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>6001.537437</td>\n",
       "      <td>6.001537e+06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>upper-5lower-digit</td>\n",
       "      <td>cracken</td>\n",
       "      <td>15.212566</td>\n",
       "      <td>14.847242</td>\n",
       "      <td>14.769393</td>\n",
       "      <td>0.138524</td>\n",
       "      <td>14.847242</td>\n",
       "      <td>cracken</td>\n",
       "      <td>14847.241614</td>\n",
       "      <td>1.484724e+07</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>upper-5lower-digit</td>\n",
       "      <td>crunch</td>\n",
       "      <td>474.109697</td>\n",
       "      <td>474.109697</td>\n",
       "      <td>474.109697</td>\n",
       "      <td>NaN</td>\n",
       "      <td>474.109697</td>\n",
       "      <td>crunch</td>\n",
       "      <td>474109.697342</td>\n",
       "      <td>4.741097e+08</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>upper-5lower-digit</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>19.390088</td>\n",
       "      <td>19.144515</td>\n",
       "      <td>18.525928</td>\n",
       "      <td>0.293365</td>\n",
       "      <td>19.144515</td>\n",
       "      <td>maskprocessor</td>\n",
       "      <td>19144.515344</td>\n",
       "      <td>1.914452e+07</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                bench           tool         max        mean         min  \\\n",
       "0           1-8digits        cracken    0.579355    0.556693    0.538694   \n",
       "1           1-8digits  maskprocessor    0.715639    0.687277    0.667732   \n",
       "2             9digits        cracken    5.045765    4.826192    4.673063   \n",
       "3             9digits         crunch  184.738300  184.738300  184.738300   \n",
       "4             9digits  maskprocessor    6.241444    6.001537    5.862338   \n",
       "5  upper-5lower-digit        cracken   15.212566   14.847242   14.769393   \n",
       "6  upper-5lower-digit         crunch  474.109697  474.109697  474.109697   \n",
       "7  upper-5lower-digit  maskprocessor   19.390088   19.144515   18.525928   \n",
       "\n",
       "        std        secs           name             ms            µs  \n",
       "0  0.012929    0.556693        cracken     556.692714  5.566927e+05  \n",
       "1  0.011805    0.687277  maskprocessor     687.276880  6.872769e+05  \n",
       "2  0.110049    4.826192        cracken    4826.191874  4.826192e+06  \n",
       "3       NaN  184.738300         crunch  184738.299608  1.847383e+08  \n",
       "4  0.101060    6.001537  maskprocessor    6001.537437  6.001537e+06  \n",
       "5  0.138524   14.847242        cracken   14847.241614  1.484724e+07  \n",
       "6       NaN  474.109697         crunch  474109.697342  4.741097e+08  \n",
       "7  0.293365   19.144515  maskprocessor   19144.515344  1.914452e+07  "
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df['secs'] = df['mean']\n",
    "df['name'] = df['tool']\n",
    "df['ms'] = df['mean'] * 1000.0\n",
    "df['µs'] = df['mean'] * 1_000_000.0\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<div id=\"altair-viz-e6de99d185114bba8c409b08009b1f3e\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-e6de99d185114bba8c409b08009b1f3e\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-e6de99d185114bba8c409b08009b1f3e\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm//vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm//vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm//vega-lite@4.8.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm//vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function loadScript(lib) {\n",
       "      return new Promise(function(resolve, reject) {\n",
       "        var s = document.createElement('script');\n",
       "        s.src = paths[lib];\n",
       "        s.async = true;\n",
       "        s.onload = () => resolve(paths[lib]);\n",
       "        s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "        document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "      });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else if (typeof vegaEmbed === \"function\") {\n",
       "      displayChart(vegaEmbed);\n",
       "    } else {\n",
       "      loadScript(\"vega\")\n",
       "        .then(() => loadScript(\"vega-lite\"))\n",
       "        .then(() => loadScript(\"vega-embed\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 400, \"continuousHeight\": 300, \"stroke\": \"transparent\"}, \"axis\": {\"domainWidth\": 0.8}}, \"data\": {\"name\": \"data-1860c3482bebcf63dab9a821ace05059\"}, \"facet\": {\"column\": {\"type\": \"nominal\", \"field\": \"name\"}}, \"spec\": {\"layer\": [{\"mark\": {\"type\": \"bar\", \"size\": 20, \"stroke\": \"transparent\"}, \"encoding\": {\"color\": {\"type\": \"nominal\", \"field\": \"bench\", \"legend\": {}, \"scale\": {\"range\": [\"#FF7B06\", \"#094AFB\", \"#D60000\"]}}, \"x\": {\"type\": \"nominal\", \"axis\": {\"labels\": false, \"title\": \"\"}, \"field\": \"bench\", \"scale\": {}}, \"y\": {\"type\": \"quantitative\", \"axis\": {\"grid\": false, \"title\": \"seconds\"}, \"field\": \"secs\", \"scale\": {\"type\": \"sqrt\"}}}, \"height\": 300, \"width\": 150}, {\"mark\": {\"type\": \"text\", \"color\": \"black\", \"dx\": 0, \"dy\": -2}, \"encoding\": {\"color\": {\"type\": \"nominal\", \"field\": \"bench\", \"legend\": {}, \"scale\": {\"range\": [\"#FF7B06\", \"#094AFB\", \"#D60000\"]}}, \"text\": {\"type\": \"quantitative\", \"field\": \"secs\"}, \"x\": {\"type\": \"nominal\", \"axis\": {\"labels\": false, \"title\": \"\"}, \"field\": \"bench\", \"scale\": {}}, \"y\": {\"type\": \"quantitative\", \"axis\": {\"grid\": false, \"title\": \"seconds\"}, \"field\": \"secs\", \"scale\": {\"type\": \"sqrt\"}}}, \"height\": 300, \"width\": 150}]}, \"title\": \"Wordlist Generation Time\", \"$schema\": \"https://vega.github.io/schema/vega-lite/v4.8.1.json\", \"datasets\": {\"data-1860c3482bebcf63dab9a821ace05059\": [{\"bench\": \"1-8digits\", \"tool\": \"cracken\", \"max\": 0.579355478286743, \"mean\": 0.5566927139405851, \"min\": 0.5386941432952881, \"std\": 0.012928925083935, \"secs\": 0.56, \"name\": \"cracken\", \"ms\": 556.692713940585, \"\\u00b5s\": 556692.713940585}, {\"bench\": \"1-8digits\", \"tool\": \"maskprocessor\", \"max\": 0.715639114379882, \"mean\": 0.687276879719325, \"min\": 0.667732000350952, \"std\": 0.011805182628674001, \"secs\": 0.69, \"name\": \"maskprocessor\", \"ms\": 687.276879719325, \"\\u00b5s\": 687276.8797193251}, {\"bench\": \"9digits\", \"tool\": \"cracken\", \"max\": 5.045764923095703, \"mean\": 4.826191873550415, \"min\": 4.673063278198242, \"std\": 0.110048711658767, \"secs\": 4.83, \"name\": \"cracken\", \"ms\": 4826.191873550415, \"\\u00b5s\": 4826191.873550415}, {\"bench\": \"9digits\", \"tool\": \" crunch\", \"max\": 184.7382996082306, \"mean\": 184.7382996082306, \"min\": 184.7382996082306, \"std\": null, \"secs\": 184.74, \"name\": \" crunch\", \"ms\": 184738.2996082306, \"\\u00b5s\": 184738299.6082306}, {\"bench\": \"9digits\", \"tool\": \"maskprocessor\", \"max\": 6.241443634033203, \"mean\": 6.001537436530704, \"min\": 5.862338304519653, \"std\": 0.10106007268655401, \"secs\": 6.0, \"name\": \"maskprocessor\", \"ms\": 6001.537436530704, \"\\u00b5s\": 6001537.436530704}, {\"bench\": \"upper-5lower-digit\", \"tool\": \"cracken\", \"max\": 15.212565660476685, \"mean\": 14.847241613599989, \"min\": 14.7693932056427, \"std\": 0.13852441829787102, \"secs\": 14.85, \"name\": \"cracken\", \"ms\": 14847.241613599988, \"\\u00b5s\": 14847241.61359999}, {\"bench\": \"upper-5lower-digit\", \"tool\": \" crunch\", \"max\": 474.10969734191895, \"mean\": 474.10969734191895, \"min\": 474.10969734191895, \"std\": null, \"secs\": 474.11, \"name\": \" crunch\", \"ms\": 474109.69734191895, \"\\u00b5s\": 474109697.34191895}, {\"bench\": \"upper-5lower-digit\", \"tool\": \"maskprocessor\", \"max\": 19.390087842941284, \"mean\": 19.144515344074794, \"min\": 18.525928020477295, \"std\": 0.29336487307277404, \"secs\": 19.14, \"name\": \"maskprocessor\", \"ms\": 19144.515344074793, \"\\u00b5s\": 19144515.344074793}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.FacetChart(...)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "make_bars_chart(\n",
    "    df,\n",
    "    title='Wordlist Generation Time',\n",
    "    sqrt_scale=True,\n",
    "    labels=False,\n",
    "    avg_col='mean',\n",
    "    width=150,\n",
    "    height=300,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'1-8digits': 0.5566927139405851,\n",
       " '9digits': 4.826191873550415,\n",
       " 'upper-5lower-digit': 14.847241613599989}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "min_took_df = df[df['tool'] == 'cracken'][['bench', 'mean']].groupby('bench').min().reset_index()\n",
    "min_took = {x.bench: x.mean for x in min_took_df.itertuples()}\n",
    "min_took"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['speedup'] = df.apply(lambda x: x['mean'] / min_took[x.bench], axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<div id=\"altair-viz-b0592e87af434bb2863247a2a3df7b4a\"></div>\n",
       "<script type=\"text/javascript\">\n",
       "  (function(spec, embedOpt){\n",
       "    let outputDiv = document.currentScript.previousElementSibling;\n",
       "    if (outputDiv.id !== \"altair-viz-b0592e87af434bb2863247a2a3df7b4a\") {\n",
       "      outputDiv = document.getElementById(\"altair-viz-b0592e87af434bb2863247a2a3df7b4a\");\n",
       "    }\n",
       "    const paths = {\n",
       "      \"vega\": \"https://cdn.jsdelivr.net/npm//vega@5?noext\",\n",
       "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm//vega-lib?noext\",\n",
       "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm//vega-lite@4.8.1?noext\",\n",
       "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm//vega-embed@6?noext\",\n",
       "    };\n",
       "\n",
       "    function loadScript(lib) {\n",
       "      return new Promise(function(resolve, reject) {\n",
       "        var s = document.createElement('script');\n",
       "        s.src = paths[lib];\n",
       "        s.async = true;\n",
       "        s.onload = () => resolve(paths[lib]);\n",
       "        s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
       "        document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "      });\n",
       "    }\n",
       "\n",
       "    function showError(err) {\n",
       "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
       "      throw err;\n",
       "    }\n",
       "\n",
       "    function displayChart(vegaEmbed) {\n",
       "      vegaEmbed(outputDiv, spec, embedOpt)\n",
       "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
       "    }\n",
       "\n",
       "    if(typeof define === \"function\" && define.amd) {\n",
       "      requirejs.config({paths});\n",
       "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
       "    } else if (typeof vegaEmbed === \"function\") {\n",
       "      displayChart(vegaEmbed);\n",
       "    } else {\n",
       "      loadScript(\"vega\")\n",
       "        .then(() => loadScript(\"vega-lite\"))\n",
       "        .then(() => loadScript(\"vega-embed\"))\n",
       "        .catch(showError)\n",
       "        .then(() => displayChart(vegaEmbed));\n",
       "    }\n",
       "  })({\"config\": {\"view\": {\"continuousWidth\": 400, \"continuousHeight\": 300, \"stroke\": \"transparent\"}, \"axis\": {\"domainWidth\": 0.8}}, \"data\": {\"name\": \"data-c2186b5326c35166b71929874a786d29\"}, \"facet\": {\"column\": {\"type\": \"nominal\", \"field\": \"name\"}}, \"spec\": {\"layer\": [{\"mark\": {\"type\": \"bar\", \"size\": 20, \"stroke\": \"transparent\"}, \"encoding\": {\"color\": {\"type\": \"nominal\", \"field\": \"bench\", \"legend\": {}, \"scale\": {\"range\": [\"#FF7B06\", \"#094AFB\", \"#D60000\"]}}, \"x\": {\"type\": \"nominal\", \"axis\": {\"labels\": false, \"title\": \"\"}, \"field\": \"bench\", \"scale\": {}}, \"y\": {\"type\": \"quantitative\", \"axis\": {\"grid\": false, \"title\": \"seconds\"}, \"field\": \"secs\", \"scale\": {\"type\": \"sqrt\"}}}, \"height\": 300, \"width\": 150}, {\"mark\": {\"type\": \"text\", \"color\": \"black\", \"dx\": 0, \"dy\": -2}, \"encoding\": {\"color\": {\"type\": \"nominal\", \"field\": \"bench\", \"legend\": {}, \"scale\": {\"range\": [\"#FF7B06\", \"#094AFB\", \"#D60000\"]}}, \"text\": {\"type\": \"quantitative\", \"field\": \"secs\"}, \"x\": {\"type\": \"nominal\", \"axis\": {\"labels\": false, \"title\": \"\"}, \"field\": \"bench\", \"scale\": {}}, \"y\": {\"type\": \"quantitative\", \"axis\": {\"grid\": false, \"title\": \"seconds\"}, \"field\": \"secs\", \"scale\": {\"type\": \"sqrt\"}}}, \"height\": 300, \"width\": 150}]}, \"title\": \"Wordlist Generation Time Speedup\", \"$schema\": \"https://vega.github.io/schema/vega-lite/v4.8.1.json\", \"datasets\": {\"data-c2186b5326c35166b71929874a786d29\": [{\"bench\": \"1-8digits\", \"tool\": \"cracken\", \"max\": 0.579355478286743, \"mean\": 0.5566927139405851, \"min\": 0.5386941432952881, \"std\": 0.012928925083935, \"secs\": 1.0, \"name\": \"cracken\", \"ms\": 556.692713940585, \"\\u00b5s\": 556692.713940585, \"speedup\": 1.0}, {\"bench\": \"1-8digits\", \"tool\": \"maskprocessor\", \"max\": 0.715639114379882, \"mean\": 0.687276879719325, \"min\": 0.667732000350952, \"std\": 0.011805182628674001, \"secs\": 1.23, \"name\": \"maskprocessor\", \"ms\": 687.276879719325, \"\\u00b5s\": 687276.8797193251, \"speedup\": 1.234571357786222}, {\"bench\": \"9digits\", \"tool\": \"cracken\", \"max\": 5.045764923095703, \"mean\": 4.826191873550415, \"min\": 4.673063278198242, \"std\": 0.110048711658767, \"secs\": 1.0, \"name\": \"cracken\", \"ms\": 4826.191873550415, \"\\u00b5s\": 4826191.873550415, \"speedup\": 1.0}, {\"bench\": \"9digits\", \"tool\": \" crunch\", \"max\": 184.7382996082306, \"mean\": 184.7382996082306, \"min\": 184.7382996082306, \"std\": null, \"secs\": 38.28, \"name\": \" crunch\", \"ms\": 184738.2996082306, \"\\u00b5s\": 184738299.6082306, \"speedup\": 38.27827497300203}, {\"bench\": \"9digits\", \"tool\": \"maskprocessor\", \"max\": 6.241443634033203, \"mean\": 6.001537436530704, \"min\": 5.862338304519653, \"std\": 0.10106007268655401, \"secs\": 1.24, \"name\": \"maskprocessor\", \"ms\": 6001.537436530704, \"\\u00b5s\": 6001537.436530704, \"speedup\": 1.24353477726853}, {\"bench\": \"upper-5lower-digit\", \"tool\": \"cracken\", \"max\": 15.212565660476685, \"mean\": 14.847241613599989, \"min\": 14.7693932056427, \"std\": 0.13852441829787102, \"secs\": 1.0, \"name\": \"cracken\", \"ms\": 14847.241613599988, \"\\u00b5s\": 14847241.61359999, \"speedup\": 1.0}, {\"bench\": \"upper-5lower-digit\", \"tool\": \" crunch\", \"max\": 474.10969734191895, \"mean\": 474.10969734191895, \"min\": 474.10969734191895, \"std\": null, \"secs\": 31.93, \"name\": \" crunch\", \"ms\": 474109.69734191895, \"\\u00b5s\": 474109697.34191895, \"speedup\": 31.932510407026527}, {\"bench\": \"upper-5lower-digit\", \"tool\": \"maskprocessor\", \"max\": 19.390087842941284, \"mean\": 19.144515344074794, \"min\": 18.525928020477295, \"std\": 0.29336487307277404, \"secs\": 1.29, \"name\": \"maskprocessor\", \"ms\": 19144.515344074793, \"\\u00b5s\": 19144515.344074793, \"speedup\": 1.2894324644477078}]}}, {\"mode\": \"vega-lite\"});\n",
       "</script>"
      ],
      "text/plain": [
       "alt.FacetChart(...)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "make_bars_chart(\n",
    "    df,\n",
    "    title='Wordlist Generation Time Speedup',\n",
    "    sqrt_scale=True,\n",
    "    labels=False,\n",
    "    avg_col='speedup',\n",
    "    width=150,\n",
    "    height=300,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>speedup</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>tool</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>crunch</th>\n",
       "      <td>35.105393</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>cracken</th>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>maskprocessor</th>\n",
       "      <td>1.255846</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                 speedup\n",
       "tool                    \n",
       " crunch        35.105393\n",
       "cracken         1.000000\n",
       "maskprocessor   1.255846"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.groupby('tool').mean()[['speedup']]"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
